package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UrlPathHelper;
import org.springframework.web.util.pattern.PathPattern;
import reactor.core.publisher.Mono;

/**
 * 自定义全局拦截器
 */
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    //匹配路径的对象
    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    @Autowired
    private RedisTemplate redisTemplate;
    //相关必须登录的页面
    @Value("${auth.allUrl}")
    private String[] allUrl;


    //判断请求 是否必须要登录
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();//请求
        ServerHttpResponse response = exchange.getResponse();//响应
        //请求路径  http://www.gmall.com    /list.html
        //请求路径  http://www.gmall.com    /api/product/inner/**  VUE Ajax  response.data.message
        //1:
        String path = request.getURI().getPath();
        if(antPathMatcher.match("/**/inner/**",path)){
            //匹配上了 此资源是内部资源 不允许网关路由
            return out(response,ResultCodeEnum.PERMISSION);
        }

        //获取用户ID
        String userId = getUserId(request);
        //2: /api/user/auth/**  auth字样的请求 要求必须登录才能访问  异步Ajax 局部刷新
        if(antPathMatcher.match("/**/auth/**",path)){
            //匹配上
            //判断用户是否登录   用户ID
            if(StringUtils.isEmpty(userId)){
                //未登录
                return out(response,ResultCodeEnum.LOGIN_AUTH);
            }

        }

        //3:匹配请求路径 trade.html 订单页面  myOrder.html 支付页面 pay.html    同步刷新页面时
        for (String url : allUrl) {
            if(path.indexOf(url) != -1 && StringUtils.isEmpty(userId)){
                //有角标
                //返回页面 由于未登录   返回登录页面 要求去登录
                // http://passport.gmall.com/login.html?originUrl=path
                //响应设置成重定向
                response.setStatusCode(HttpStatus.SEE_OTHER);
                //响应重定向的URL
                response.getHeaders().set(HttpHeaders.LOCATION,
                        "http://passport.gmall.com/login.html?originUrl="
                                + request.getURI().getRawSchemeSpecificPart());
                // http://cart.gmall.com/trade.html
                System.out.println("完整的URL：" + request.getURI().getRawSchemeSpecificPart());
                return response.setComplete();//响应回浏览器
            }

        }
        //其它请求 不需要登录  不是内部请求   正常放行
        //是否需要将用户ID 传递给后面微服务
        //网关 要将用户ID 传递给后面的微服务  登录传递 不登录
        if(!StringUtils.isEmpty(userId)){
            //传递给后面的微服务
            //请求头中 设置用户ID   K:userId V:3
            request.mutate().header("userId",userId);
        }
        //传递临时用户
        String userTempId = getUserTempId(request);
        if(!StringUtils.isEmpty(userTempId)){
            request.mutate().header("userTempId",userTempId);
        }
        //正常放行
        return chain.filter(exchange);
    }

    //返回值响应Result实体
    private Mono<Void> out(ServerHttpResponse response,ResultCodeEnum resultCodeEnum) {

        Result<Object> result = Result.build(null, resultCodeEnum);
        byte[] bytes = JSON.toJSONString(result).getBytes();
        DataBuffer dataBuffer = response.bufferFactory().wrap(bytes);
        //响应头
        //响应体  Result转成二进制  中文不乱码
        response.getHeaders().set(HttpHeaders.CONTENT_TYPE,"application/json;charset=utf-8");
        return response.writeWith(Mono.just(dataBuffer));

    }

    //获取临时用户的方法
    public String getUserTempId(ServerHttpRequest request){
        //userTempId  请求头
        String userTempId = request.getHeaders().getFirst("userTempId");//""
        if(StringUtils.isEmpty(userTempId)) {
            //请求头中没有  从Cookie获取
            HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
            if (httpCookie != null) {
                userTempId = httpCookie.getValue();
            }
        }
        return userTempId;
    }


    //获取用户ID  令牌 从Redis缓存中获取出用户ID    K：令牌 V：用户ID
    public String getUserId(ServerHttpRequest request){
        //获取令牌  从请求头中  从Cookie
        String token = request.getHeaders().getFirst("token");//""
        if(StringUtils.isEmpty(token)){
            //请求头中没有  从Cookie获取
            HttpCookie httpCookie = request.getCookies().getFirst("token");
            if(httpCookie != null){
                token = httpCookie.getValue();
            }
        }
        if(!StringUtils.isEmpty(token)){
            //此令牌在缓存中是否也存在  存在取出 用户ID
            if(redisTemplate.hasKey("user:login:" + token)){
                //获取用户ID
                return (String) redisTemplate.opsForValue().get("user:login:" + token);
            }
        }
        return null;

    }








    //网关默认有9大拦截器  + 自定义的拦截器  请执行哪一个拦截器   负最大整数 0 正最大整数
    @Override
    public int getOrder() {
        return 0;
    }
}
